using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;

namespace Mytest666
{
    public class User
    {
        [MyNumber(ErrorMessage = "Id必须全部为数字")]
        public int Id { get; set; }

        [MyEmpty(ErrorMessage = "用户名不能为空")]
        public string Name { get; set; }

        [MyEmpty]
        [MyPhone(ErrorMessage = "这不是手机号")]
        public long Phone { get; set; }

        [MyEmpty]
        [MyEmail]
        public string Email { get; set; }
    }
    class Program
    {
        static void Main(string[] args)
        {
            List<object> users = new List<object>()
            {
                new User
                {
                    Id = 0
                },
                new User
                {
                    Id=1,
                    Name="痴者工良",
                    Phone=13510070650,
                    Email="666@qq.com"
                },
                new User
                {
                    Id=2,
                    Name="NCC牛逼",
                    Phone=6666666,
                    Email="NCC@NCC.NCC"
                }
            };

            Analysis(users);

            Console.ReadKey();
        }

        /// <summary>
        /// 解析功能
        /// </summary>
        /// <param name="list"></param>
        private static void Analysis(List<object> list)
        {
            foreach (var item in list)
            {
                Console.WriteLine("\n\n检查对象属性是否通过检查");
                // 获取实例对象的类型
                Type type = item.GetType();
                // 获取类的属性列表
                PropertyInfo[] properties = type.GetProperties();

                // 对每个属性进行检查，是否符合要求
                foreach (PropertyInfo itemNode in properties)
                {
                    Console.WriteLine($"\n属性：{itemNode.Name}，值为 {itemNode.GetValue(item)}");
                    // 此属性的所有特性
                    IEnumerable<Attribute> attList = itemNode.GetCustomAttributes();
                    if (attList != null)
                    {
                        // 开始对属性进行特性验证
                        foreach (Attribute itemNodeNode in attList)
                        {
                            // 如果不是我们自定义的验证特性，则跳过
                            if (!IsMyValidationAttribute(itemNodeNode))
                                continue;
                            var result = StartValid(itemNodeNode, itemNode, item);

                            // 验证跳过，提示消息
                            if (result.Item1)
                            {
                                Console.WriteLine($"通过了 {itemNodeNode.GetType().Name} 验证");
                            }
                            // 没通过验证的话
                            else
                            {
                                Console.WriteLine($"未通过了 {itemNodeNode.GetType().Name} 验证，报错信息： {result.Item2}");
                            }
                        }
                    }
                    Console.WriteLine("*****属性分割线******");
                }
                Console.WriteLine("########对象分割线########");
            }
        }

        /// <summary>
        /// 验证此属性是否通过验证，只能验证 继承了 MyValidationAttribute 的属性
        /// </summary>
        /// <param name="attr">属性带有的特性</param>
        /// <param name="property">要验证的属性</param>
        /// <param name="obj">实例对象</param>
        /// <returns></returns>
        private static (bool, string) StartValid(Attribute attr, PropertyInfo property, object obj)
        {
            // 指定获取实例对象的属性值
            object value = property.GetValue(obj);
            // 获取特性的 IsValid 方法
            MethodInfo attrMethod = attr.GetType().GetMethod("IsValid", new Type[] { typeof(object) });
            // 获取特性的 IsValid 属性
            PropertyInfo attrProperty = attr.GetType().GetProperty("ErrorMessage");

            // 开始检查，获取检查结果
            bool checkResult = (bool)attrMethod.Invoke(attr, new object[] { value });

            // 获取特性的 ErrorMessage 属性
            string errorMessage = (string)attrProperty.GetValue(attr);

            // 通过验证的话，就没有报错信息
            if (checkResult == true)
                return (true, null);

            // 验证不通过，返回预定义的信息
            return (false, errorMessage);
        }
        /// <summary>
        /// 检查特性是否属于 MyValidationAttribute 类型的特性
        /// </summary>
        /// <param name="attribute">要检查的特性</param>
        /// <returns></returns>
        private static bool IsMyValidationAttribute(Attribute attribute)
        {
            Type type = attribute.GetType();
            return type.BaseType == typeof(MyValidationAttribute);
        }
    }

    #region 自定义验证特性

    /// <summary>
    /// 自定义验证特性的抽象类
    /// </summary>
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
    public abstract class MyValidationAttribute : Attribute
    {
        private string Message;
        /// <summary>
        /// 验证不通过时，提示信息
        /// </summary>
        public string ErrorMessage
        {
            get
            {
                return string.IsNullOrEmpty(Message) ? "默认报错" : Message;
            }
            set
            {
                Message = value;
            }
        }

        /// <summary>
        /// 检查验证是否通过
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public virtual bool IsValid(object value)
        {
            return value == null ? false : true;
        }
    }

    /// <summary>
    /// 标识属性或字段不能为空
    /// </summary>
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
    public class MyEmptyAttribute : MyValidationAttribute
    {
        /// <summary>
        /// 验证是否为空
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public override bool IsValid(object value)
        {
            if (value == null)
                return false;

            if (string.IsNullOrEmpty(value.ToString()))
                return false;
            return true;
        }
    }

    /// <summary>
    /// 是否是手机号格式
    /// </summary>
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
    public class MyPhoneAttribute : MyValidationAttribute
    {
        public override bool IsValid(object value)
        {
            if (value == null)
                return false;

            if (string.IsNullOrEmpty(value.ToString()))
                return false;

            string pattern = "^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|166|198|199|(147))\\d{8}$";
            Regex regex = new Regex(pattern);
            return regex.IsMatch(value.ToString());
        }
    }

    /// <summary>
    /// 是否是邮箱格式
    /// </summary>
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
    public class MyEmailAttribute : MyValidationAttribute
    {
        public override bool IsValid(object value)
        {
            if (value == null)
                return false;

            if (string.IsNullOrEmpty(value.ToString()))
                return false;

            string pattern = @"^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$";
            Regex regex = new Regex(pattern);
            return regex.IsMatch(value.ToString());
        }
    }

    /// <summary>
    /// 是否全是数字
    /// </summary>
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
    public class MyNumberAttribute : MyValidationAttribute
    {
        public override bool IsValid(object value)
        {
            if (value == null)
                return false;

            if (string.IsNullOrEmpty(value.ToString()))
                return false;

            string pattern = "^[0-9]*$";
            Regex regex = new Regex(pattern);
            return regex.IsMatch(value.ToString());
        }
    }

    #endregion
}